<?php

class BackupManager extends TModule
{
	static $BACKUP_DIR = 'data/backups';
	static $BACKUP_META_FILE = 'backups.xml';
	static $DEFAULT_DB_CREATE_SCRIPT 
			= 'protected/Database/create_empty_db.sql';

    public $timestampFormat = "d_m_Y_Gis";
	public $sqlFileExtansion = 'sql';

    private $dbname = null;
    private $dbhost = null;
    private $dbuser = null;
    private $dbpassword = null;
    
    private $dbConnection;
	
    public function __construct()
    {
    	$this -> dbConnection = $this -> Application -> Modules['database'] -> getDatabase();
    	
    	// fill the access data:
    	$accessData = $this -> getDatabaseAccessData();
    	$this -> dbname = $accessData['dbname'];
    	$this -> dbhost = $accessData['dbhost'];
    	$this -> dbuser = $accessData['dbuser'];
    	$this -> dbpassword = $accessData['dbpassword'];
    	
    	/*echo 'dbname = '.$this->dbname.'<br />';
    	echo 'dbhost = '.$this->dbhost.'<br />';
    	echo 'dbuser = '.$this->dbuser.'<br />';
    	echo 'dbpassword = '.$this->dbpassword;*/
    	//$this -> restoreDefaults();
    }
    
	// -------------------- basic functions --------------------
	public function addBackup($date, $description)
	{
		// make filename:
        $filename = $this -> getFileNameFromDate($date);

		// dump current database:
        $result = $this -> dumpDatabase($filename);
       	if ($result == FALSE) {
       		return null;
       	}
        
        // add new backup to the metafile:
        $backupRecord = new BackupRecord();
        $backupRecord -> setData($date, $description, $filename);
        $this -> addBackupToXML($backupRecord);
        return $backupRecord;
	}
	
	public function restoreBackup($filename) {
		$this -> loadScript(BackupManager::$BACKUP_DIR.'/drop_all_tables.sql');
		$result = $this -> loadScript($filename);
		if ($result == FALSE)
			return null;
	}
	
	public function removeBackup($date)
	{
		foreach ($this -> getBackupsList() as $backup)
			if ($backup -> getDate() == $date)
				$this -> removeBackupFromXML($backup);
		
		unlink($this -> getFileNameFromDate($date));
	}
	
	public function getBackupByFilename($filename)
	{
		$backupList = getBackupsList();
		foreach ($backupList as $backup)
			if ($backup -> getFilename() == $filename)
				return $backup;
		return null;
	}
	
	public function countBackups() {
		return count($this -> getBackupsList());
	}
	
    // -------------------- extended functions --------------------
    public function getBackupsList($revert = false, $offset = -1, $limit = -1)
    {
    	$doc = new DOMDocument();
    	$doc -> load(BackupManager::$BACKUP_DIR.'/'.BackupManager::$BACKUP_META_FILE);
    	$backups = $doc -> getElementsByTagName('backup');
    	$backupRecords = Array();
    	foreach ($backups as $i => $backup)
    	{
    		if ($backup == null)
    			continue;
    		
    		$date = $backup -> getElementsByTagName('date');
    		$date = $date -> item(0) -> nodeValue;
    		
    		$filename = $backup -> getElementsByTagName('filename');
    		$filename = $filename -> item(0) -> nodeValue;
    		
    		$comment = $backup -> getElementsByTagName('comment');
    		$comment = $comment -> item(0) -> nodeValue;
    		
    		$backupRecord = new BackupRecord;
    		$backupRecord -> setData($date, $comment, $filename);
    		$backupRecords[$i] = $backupRecord;
    	}
    	
    	$backupsNumber = count($backupRecords);
    	
    	if($offset < 0 || $offset == null)
			$offset = 0;
		if($limit < 0 || $limit == null)
			$limit = $backupsNumber;

    	return array_slice($backupRecords, $offset, $limit);
    }
    
    public function restoreDefaults()
    {
		$this -> loadScript(BackupManager::$BACKUP_DIR.'/drop_all_tables.sql');    	
    	$this -> loadScript(BackupManager::$DEFAULT_DB_CREATE_SCRIPT);
    }
    
    // -------------------- private functions --------------------
    private function loadScript($filename) {
    	if($this->dbpassword)
        	$command = sprintf("mysql %s -h %s -u%s -p%s < %s",
            	$this->dbname, $this->dbhost, $this->dbuser,
            	$this->dbpassword, $filename);
        else
        	$command = sprintf("mysql %s -h %s -u%s < %s",
            	$this->dbname, $this->dbhost, $this->dbuser,
            	$filename);

        $result = system($command);
        return $result; // result is FALSE if something went wrong
	}
    
    private function dumpDatabase($filename)
	{
		if($this->dbpassword)
			$command = sprintf("mysqldump %s -h %s -u%s -p%s > %s",
	            $this->dbname, $this->dbhost, $this->dbuser,
            	$this->dbpassword, $filename);
        else
        	$command = sprintf("mysqldump %s -h %s -u%s > %s",
	            $this->dbname, $this->dbhost, $this->dbuser,
            	$filename);

        system($command);
        
        // check if file exists or if it is not empty:
        $result = TRUE;
        
        if (!file_exists($filename))
        	$result = FALSE;
        	
        else if (filesize($filename) == 0)
        {
        	$result = FALSE;
        	unlink($filename);
        }
        
        return $result; // result is FALSE if something went wrong
	}
	
	private function addBackupToXML(BackupRecord $backupRecord)
	{
		$list = $this -> getBackupsList();
		$list[] = $backupRecord;
		$xml = $this -> convertBackupListToXML($list);
		$this -> writeXMLToFile($xml);
	}
	
	private function removeBackupFromXML(BackupRecord $backupRecord)
	{
		$list = $this -> getBackupsList();
		foreach ($list as $i => $backup)
			if ($backup == $backupRecord)
				$list[$i] = null;
		
		$xml = $this -> convertBackupListToXML($list);
		$this -> writeXMLToFile($xml);
	}
	
	private function convertBackupListToXML($list) {
		$xml = '<?xml version="1.0" encoding="utf-8"?>'."\n"
			.'<backups>'."\n";
			
		foreach ($list as $i => $backup) 
		{
			if ($list[$i] == null)
				continue;
			
			$xml .= "\t".'<backup>'."\n";
			$xml .= "\t\t".'<date>';
			$xml .= $backup -> getDate();
			$xml .= '</date>'."\n";
			
			$xml .= "\t\t".'<filename>';
			$xml .= $backup -> getFilename();
			$xml .= '</filename>'."\n";
			
			$xml .= "\t\t".'<comment>';
			$xml .= $backup -> getComment();
			$xml .= '</comment>'."\n";
			
			$xml .= "\t".'</backup>'."\n";
		}
		
		$xml .= '</backups>';
		
		return $xml;
	}
    
	private function getFileNameFromDate($date)
	{
		$dt = new DateTime($date);
		return BackupManager::$BACKUP_DIR.'/'.$dt->format($this->timestampFormat)
                    .'.'
                    .$this->sqlFileExtansion;
	}
	
	private function writeXMLToFile($xmlstr) {
		$file = BackupManager::$BACKUP_DIR.'/'.BackupManager::$BACKUP_META_FILE;
		$fh = fopen($file, 'w' ) or die ("can't create file");
	    fwrite($fh, $xmlstr);
	    fclose($fh);
	}
	
	private function getDatabaseAccessData() // returns access[] 
	{
		$access = array();
		$dbConnectionString = $this -> dbConnection -> getConnectionString();
    		
    	// get db name and db host:
    	$dbhostRegexp = '/host\=(.+);/';
    	$dbnameRegexp= '/dbname\=(.+)/';
    	
    	preg_match_all($dbnameRegexp, $dbConnectionString, $matches);
    	$dbname = $matches[1][0];
    	
    	preg_match_all($dbhostRegexp, $dbConnectionString, $matches);
    	$dbhost= $matches[1][0];
    	
    	// collect data:
    	$access['dbname'] = $dbname;
    	$access['dbhost'] = $dbhost;
    	$access['dbuser'] = $this -> dbConnection -> getUsername();
    	$access['dbpassword'] = $this -> dbConnection -> getPassword();
    	
    	return $access;
	}
}

?>